package com.yang.demo.client;

import com.fasterxml.jackson.core.type.TypeReference;
import com.yang.demo.config.ConfigManager;
import com.yang.demo.model.HttpResponse;
import com.yang.demo.util.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.hc.client5.http.async.methods.SimpleHttpRequest;
import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder;
import org.apache.hc.client5.http.config.ConnectionConfig;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager;
import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;
import org.apache.hc.client5.http.ssl.ClientTlsStrategyBuilder;
import org.apache.hc.core5.concurrent.FutureCallback;
import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.HttpHeaders;
import org.apache.hc.core5.http.HttpStatus;
import org.apache.hc.core5.http.nio.ssl.TlsStrategy;
import org.apache.hc.core5.http2.HttpVersionPolicy;
import org.apache.hc.core5.io.CloseMode;
import org.apache.hc.core5.ssl.SSLContexts;
import org.apache.hc.core5.util.TimeValue;
import org.apache.hc.core5.util.Timeout;

import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

/**
 * RestClient主类
 * 提供HTTP请求的完整实现，支持同步和异步调用
 */
@Slf4j
public class RestClient {

    private final ConfigManager configManager;
    private final CloseableHttpAsyncClient httpClient;
    private final Map<String, String> defaultHeaders;

    public RestClient() {
        this.configManager = ConfigManager.getInstance();
        this.httpClient = createHttpClient();
        this.defaultHeaders = new HashMap<>();
        initDefaultHeaders();
        this.httpClient.start();
    }

    /**
     * 创建HTTP客户端
     */
    private CloseableHttpAsyncClient createHttpClient() {
        try {
            // 创建SSL上下文
            SSLContext sslContext = SSLContexts.createDefault();

            // 创建TLS策略
            TlsStrategy tlsStrategy = ClientTlsStrategyBuilder.create()
                    .setSslContext(sslContext)
                    .build();

            // 创建连接池配置
            PoolingAsyncClientConnectionManager connectionManager = PoolingAsyncClientConnectionManagerBuilder.create()
                    .setTlsStrategy(tlsStrategy)
                    .setMaxConnTotal(configManager.getConnectionPoolMaxTotal())
                    .setMaxConnPerRoute(configManager.getConnectionPoolDefaultMaxPerRoute())
                    .setConnectionTimeToLive(TimeValue.ofMinutes(5))
                    .build();

            // 创建请求配置
            RequestConfig requestConfig = RequestConfig.custom()
                    .setConnectionRequestTimeout(Timeout.ofMilliseconds(configManager.getConnectionRequestTimeout()))
                    .setResponseTimeout(Timeout.ofMilliseconds(configManager.getTotalTimeout()))
                    .build();

            // 创建连接配置
            ConnectionConfig connectionConfig = ConnectionConfig.custom()
                    .setConnectTimeout(Timeout.ofMilliseconds(configManager.getConnectTimeout()))
                    .setSocketTimeout(Timeout.ofMilliseconds(configManager.getSocketTimeout()))
                    .setValidateAfterInactivity(TimeValue.ofMilliseconds(configManager.getConnectionPoolValidateAfterInactivity()))
                    .build();

            connectionManager.setDefaultConnectionConfig(connectionConfig);

            // 创建HTTP客户端
            return HttpAsyncClients.custom()
                    .setConnectionManager(connectionManager)
                    .setDefaultRequestConfig(requestConfig)
                    .setVersionPolicy(HttpVersionPolicy.FORCE_HTTP_2)
                    .build();

        } catch (Exception e) {
            log.error("创建HTTP客户端失败", e);
            throw new RuntimeException("创建HTTP客户端失败", e);
        }
    }

    /**
     * 初始化默认请求头
     */
    private void initDefaultHeaders() {
        defaultHeaders.put(HttpHeaders.USER_AGENT, configManager.getUserAgent());
        defaultHeaders.put(HttpHeaders.ACCEPT, ContentType.APPLICATION_JSON.getMimeType());

        if (configManager.isCompressionEnabled()) {
            defaultHeaders.put(HttpHeaders.ACCEPT_ENCODING, configManager.getAcceptEncoding());
        }

        defaultHeaders.put(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.getMimeType());
    }

    /**
     * 添加默认请求头
     */
    public void addDefaultHeader(String name, String value) {
        defaultHeaders.put(name, value);
    }

    /**
     * 移除默认请求头
     */
    public void removeDefaultHeader(String name) {
        defaultHeaders.remove(name);
    }

    /**
     * GET请求
     */
    public HttpResponse<String> get(String url) {
        return get(url, new HashMap<>());
    }

    public HttpResponse<String> get(String url, Map<String, String> headers) {
        return execute("GET", url, null, headers);
    }

    public <T> HttpResponse<T> get(String url, Class<T> responseType) {
        return get(url, new HashMap<>(), responseType);
    }

    public <T> HttpResponse<T> get(String url, Map<String, String> headers, Class<T> responseType) {
        HttpResponse<String> response = get(url, headers);
        return parseResponse(response, responseType);
    }

    public <T> HttpResponse<T> get(String url, TypeReference<T> responseType) {
        return get(url, new HashMap<>(), responseType);
    }

    public <T> HttpResponse<T> get(String url, Map<String, String> headers, TypeReference<T> responseType) {
        HttpResponse<String> response = get(url, headers);
        return parseResponse(response, responseType);
    }

    /**
     * POST请求
     */
    public HttpResponse<String> post(String url, Object body) {
        return post(url, body, new HashMap<>());
    }

    public HttpResponse<String> post(String url, Object body, Map<String, String> headers) {
        return execute("POST", url, body, headers);
    }

    public <T> HttpResponse<T> post(String url, Object body, Class<T> responseType) {
        return post(url, body, new HashMap<>(), responseType);
    }

    public <T> HttpResponse<T> post(String url, Object body, Map<String, String> headers, Class<T> responseType) {
        HttpResponse<String> response = post(url, body, headers);
        return parseResponse(response, responseType);
    }

    public <T> HttpResponse<T> post(String url, Object body, TypeReference<T> responseType) {
        return post(url, body, new HashMap<>(), responseType);
    }

    public <T> HttpResponse<T> post(String url, Object body, Map<String, String> headers, TypeReference<T> responseType) {
        HttpResponse<String> response = post(url, body, headers);
        return parseResponse(response, responseType);
    }

    /**
     * PUT请求
     */
    public HttpResponse<String> put(String url, Object body) {
        return put(url, body, new HashMap<>());
    }

    public HttpResponse<String> put(String url, Object body, Map<String, String> headers) {
        return execute("PUT", url, body, headers);
    }

    public <T> HttpResponse<T> put(String url, Object body, Class<T> responseType) {
        return put(url, body, new HashMap<>(), responseType);
    }

    public <T> HttpResponse<T> put(String url, Object body, Map<String, String> headers, Class<T> responseType) {
        HttpResponse<String> response = put(url, body, headers);
        return parseResponse(response, responseType);
    }

    public <T> HttpResponse<T> put(String url, Object body, TypeReference<T> responseType) {
        return put(url, body, new HashMap<>(), responseType);
    }

    public <T> HttpResponse<T> put(String url, Object body, Map<String, String> headers, TypeReference<T> responseType) {
        HttpResponse<String> response = put(url, body, headers);
        return parseResponse(response, responseType);
    }

    /**
     * DELETE请求
     */
    public HttpResponse<String> delete(String url) {
        return delete(url, new HashMap<>());
    }

    public HttpResponse<String> delete(String url, Map<String, String> headers) {
        return execute("DELETE", url, null, headers);
    }

    public <T> HttpResponse<T> delete(String url, Class<T> responseType) {
        return delete(url, new HashMap<>(), responseType);
    }

    public <T> HttpResponse<T> delete(String url, Map<String, String> headers, Class<T> responseType) {
        HttpResponse<String> response = delete(url, headers);
        return parseResponse(response, responseType);
    }

    public <T> HttpResponse<T> delete(String url, TypeReference<T> responseType) {
        return delete(url, new HashMap<>(), responseType);
    }

    public <T> HttpResponse<T> delete(String url, Map<String, String> headers, TypeReference<T> responseType) {
        HttpResponse<String> response = delete(url, headers);
        return parseResponse(response, responseType);
    }

    /**
     * 执行HTTP请求
     */
    private HttpResponse<String> execute(String method, String url, Object body, Map<String, String> headers) {
        long startTime = System.currentTimeMillis();

        try {
            // 合并默认请求头和自定义请求头
            Map<String, String> allHeaders = new HashMap<>(defaultHeaders);
            if (headers != null) {
                allHeaders.putAll(headers);
            }

            // 创建请求
            SimpleRequestBuilder requestBuilder = SimpleRequestBuilder.create(method)
                    .setUri(URI.create(url));

            // 设置请求头
            allHeaders.forEach(requestBuilder::setHeader);

            // 设置请求体
            if (body != null) {
                String bodyContent;
                if (body instanceof String) {
                    bodyContent = (String) body;
                } else {
                    bodyContent = JsonUtils.toJson(body);
                }
                requestBuilder.setBody(bodyContent, ContentType.APPLICATION_JSON);
            }

            SimpleHttpRequest request = requestBuilder.build();

            if (configManager.isLoggingEnabled()) {
                logRequest(request);
            }

            // 执行请求
            CompletableFuture<SimpleHttpResponse> future = new CompletableFuture<>();
            httpClient.execute(request, new FutureCallback<SimpleHttpResponse>() {
                @Override
                public void completed(SimpleHttpResponse result) {
                    future.complete(result);
                }

                @Override
                public void failed(Exception ex) {
                    future.completeExceptionally(ex);
                }

                @Override
                public void cancelled() {
                    future.completeExceptionally(new RuntimeException("请求被取消"));
                }
            });

            SimpleHttpResponse response = future.get(configManager.getTotalTimeout(), TimeUnit.MILLISECONDS);
            long endTime = System.currentTimeMillis();

            HttpResponse<String> httpResponse = buildResponse(response, endTime - startTime);

            if (configManager.isLoggingEnabled()) {
                logResponse(httpResponse);
            }

            return httpResponse;

        } catch (Exception e) {
            long endTime = System.currentTimeMillis();
            log.error("HTTP请求失败: {} {}", method, url, e);
            return HttpResponse.<String>builder()
                    .statusCode(HttpStatus.SC_INTERNAL_SERVER_ERROR)
                    .message("请求失败: " + e.getMessage())
                    .responseTime(endTime - startTime)
                    .build();
        }
    }

    /**
     * 构建响应对象
     */
    private HttpResponse<String> buildResponse(SimpleHttpResponse response, long responseTime) {
        Map<String, String> headers = new HashMap<>();
        for (org.apache.hc.core5.http.Header header : response.getHeaders()) {
            headers.put(header.getName(), header.getValue());
        }

        return HttpResponse.<String>builder()
                .statusCode(response.getCode())
                .message(response.getReasonPhrase())
                .headers(headers)
                .body(response.getBodyText())
                .responseTime(responseTime)
                .build();
    }

    /**
     * 解析响应
     */
    private <T> HttpResponse<T> parseResponse(HttpResponse<String> response, Class<T> responseType) {
        HttpResponse<T> result = HttpResponse.<T>builder()
                .statusCode(response.getStatusCode())
                .message(response.getMessage())
                .headers(response.getHeaders())
                .responseTime(response.getResponseTime())
                .build();

        if (response.getBody() != null && !response.getBody().isEmpty()) {
            try {
                result.setData(JsonUtils.fromJson(response.getBody(), responseType));
            } catch (Exception e) {
                log.warn("解析响应体失败: {}", e.getMessage());
                // 如果解析失败，尝试直接转换
                if (responseType == String.class) {
                    result.setData((T) response.getBody());
                }
            }
        }

        return result;
    }

    /**
     * 解析响应（泛型版本）
     */
    private <T> HttpResponse<T> parseResponse(HttpResponse<String> response, TypeReference<T> responseType) {
        HttpResponse<T> result = HttpResponse.<T>builder()
                .statusCode(response.getStatusCode())
                .message(response.getMessage())
                .headers(response.getHeaders())
                .responseTime(response.getResponseTime())
                .build();

        if (response.getBody() != null && !response.getBody().isEmpty()) {
            try {
                result.setData(JsonUtils.fromJson(response.getBody(), responseType));
            } catch (Exception e) {
                log.warn("解析响应体失败: {}", e.getMessage());
            }
        }

        return result;
    }

    /**
     * 记录请求日志
     */
    private void logRequest(SimpleHttpRequest request) throws URISyntaxException {
        if (configManager.isLogRequestHeaders()) {
            log.info("发送请求: {} {}", request.getMethod(), request.getUri());
            for (org.apache.hc.core5.http.Header header : request.getHeaders()) {
                log.info("请求头: {} = {}", header.getName(), header.getValue());
            }
        } else {
            log.info("发送请求: {} {}", request.getMethod(), request.getUri());
        }
    }

    /**
     * 记录响应日志
     */
    private void logResponse(HttpResponse<String> response) {
        if (configManager.isLogResponseHeaders()) {
            log.info("收到响应: {} {} ({}ms)", response.getStatusCode(), response.getMessage(), response.getResponseTime());
            if (response.getHeaders() != null) {
                response.getHeaders().forEach((key, value) ->
                    log.info("响应头: {} = {}", key, value));
            }
        } else {
            log.info("收到响应: {} {} ({}ms)", response.getStatusCode(), response.getMessage(), response.getResponseTime());
        }
    }

    /**
     * 关闭客户端
     */
    public void close() {
        if (httpClient != null) {
            httpClient.close(CloseMode.GRACEFUL);
            log.info("RestClient已关闭");
        }
    }
}